package main

import (
	"flag"
	"fmt"
	"os"
	"runtime"
	"sync"

	"github.com/BurntSushi/toml"
	"github.com/agtorre/gocolorize"
	"github.com/mijia/gobuildweb/assets"
	"github.com/mijia/gobuildweb/loggers"
)

type ProjectConfig struct {
	sync.RWMutex
	Package      *PackageConfig
	Assets       *assets.Config
	Distribution *DistributionConfig
}

func (pc ProjectConfig) getAssetEntry(entryName string) (*assets.Entry, bool) {
	pc.RLock()
	defer pc.RUnlock()
	return assets.GetEntryConfig(*pc.Assets, entryName)
}

type PackageConfig struct {
	Name         string
	Version      string
	Authors      []string
	Dependencies []string `toml:"deps"`
	Builder      string   `toml:builder`
	BuildOpts    []string `toml:"build_opts"`
	OmitTests    []string `toml:"omit_tests"`
	IsGraceful   bool     `toml:"is_graceful"`
}

func (p *PackageConfig) IsEqual(pp *PackageConfig) bool {
	return p.Name == pp.Name &&
	p.Version == pp.Version &&
	p.Builder == pp.Builder &&
	p.IsGraceful == pp.IsGraceful &&
	stringListIsEqual(p.BuildOpts, pp.BuildOpts) &&
	stringListIsEqual(p.OmitTests, pp.OmitTests)
}

type DistributionConfig struct {
	BuildOpts    []string    `toml:"build_opts"`
	PackExtras   []string    `toml:"pack_extras"`
	CrossTargets [][2]string `toml:"cross_targets"`
	ExtraCmd     []string    `toml:"extra_cmd"`
}

func usage() {
	fmt.Println("Usage:")
	fmt.Println("  run       Build assets and binary, and then watch your file changes and run the application")
	fmt.Println("  watch     Just watch your file changes and run the application without building")
	fmt.Println("  dist      Build your web application")
	os.Exit(1)
}

func main() {
	loggers.IsDebug = os.Getenv("GBW_DEBUG") == "1"
	fmt.Println(gocolorize.NewColor("magenta").Paint("gobuildweb > Build a Golang web application.\n"))

	cmds := map[string]Command{
		"run":  commandRun,
		"dist": commandDist,
		"watch": commandWatch,
	}
	flag.Parse()
	args := flag.Args()
	if len(args) == 0 {
		usage()
	}
	if cmd, ok := cmds[args[0]]; !ok {
		usage()
	} else {
		if fi, err := os.Stat("project.toml"); os.IsNotExist(err) {
			loggers.ERROR.Fatalf("Please provide a project.toml for web project.")
		} else if err != nil {
			loggers.ERROR.Fatalf("Accessing project.toml file error, %v.", err)
		} else if fi.IsDir() {
			loggers.ERROR.Fatalf("project.toml cannot be a directory.")
		}

		if _, err := toml.DecodeFile("project.toml", &rootConfig); err != nil {
			loggers.ERROR.Fatalf("Cannot decode the project.toml into TOML format, %v", err)
		}

		loggers.SUCC.Printf("Loaded project.toml... %s", rootConfig.Package.Name)
		if err := cmd(args[1:]); err != nil {
			loggers.ERROR.Fatalf("Executing command [%v] error, %v", args[0], err)
		}
	}
}

var rootConfig ProjectConfig

func init() {
	runtime.GOMAXPROCS(runtime.NumCPU())
}
